#include <gtk/gtk.h>
#include "tsapp.h"
#include "tsappwin.h"
#include <json-glib/json-glib.h>
#include <glib/gstdio.h>
#define TMP_PROTOCOL_TCP_CLIENT	"tcp client"
#define TMP_PROTOCOL_TCP_SERVER	"tcp server"
#define TMP_PROTOCOL_UDP	"udp"
#define TMP_STATUS_OPENED	"server opened"
#define TMP_STATUS_CLOSED	"server closed"
#define TMP_BUTTON_CLOSE	"close server"
#define TMP_BUTTON_OPEN		"open server"
#define TMP_BUTTON_CONNECT	"connect"
#define TMP_BUTTON_DISCONNECT	"disconnect"
struct _TsAppWindow
{
  GtkApplicationWindow parent;
};

typedef struct _TsAppWindowPrivate TsAppWindowPrivate;

struct _TsAppWindowPrivate
{
  GSettings *settings;
	GtkWidget *protocol;
	GtkWidget *ip_label;
	GtkWidget *ip;
	GtkWidget *port;
	GtkWidget *local_port;
	GtkWidget *connect;

	GtkWidget *clients;
	GtkWidget *enter;

	GtkWidget *input;
	GtkWidget *use_hex;

	GtkWidget *msg_scrolled;
	GtkWidget *msg_box;

	GtkWidget *status;
	gpointer socket;
};

G_DEFINE_TYPE_WITH_PRIVATE(TsAppWindow, ts_app_window, GTK_TYPE_APPLICATION_WINDOW);

void *update_config(const char *filename, const char *key, const char *value);
void *sys_uint8_print(const char *name, const uint8_t *buf, int len)
{
	int i;

	printf("[%4d]%16s", len, name);
	for (i = 0; i < len; i ++ ) {
		printf("%02x ", buf[i]);
	}
	printf("\n");

	return NULL;
}
char *sys_uint8_to_str_calloc(const uint8_t *msg, int len)
{
	char *res = NULL;
	int size = 0, i = 0;

	size = len * 3;
	res = calloc(1, size + 1);
	for (i = 0; i < len; i++) {
		snprintf(res + (i * 3), 4, "%02x ", msg[i]);
	}
	return res;
}
void *msg_add(gpointer data, const gchar *name, const gchar *msg, gsize len,
		gboolean dir)
{
	gboolean use_hex = FALSE;
	gchar *show = NULL;
	GtkWidget *msg_box, *row, *box, *label;//, *msg_scrolled;
	TsAppWindow *win;
	TsAppWindowPrivate *priv;

	win = data;
	priv = ts_app_window_get_instance_private (win);
	//msg_scrolled = priv->msg_scrolled;
	msg_box = priv->msg_box;

	g_print("msg show:%ld\n", len);
	row = gtk_list_box_row_new();
  if (!dir) {
    g_debug ("blue");
    gtk_widget_set_name(row, "my-widget");
    GtkCssProvider *provider = gtk_css_provider_new();
    // Set the background color of the widget using CSS selector
    const char *css = "#my-widget { background-color: blue; }";
    gtk_css_provider_load_from_data(provider, css, -1, NULL);
    // Apply the CSS stylesheet to the widget
    GtkStyleContext *context = gtk_widget_get_style_context(row);
    gtk_style_context_add_provider(context, GTK_STYLE_PROVIDER(provider),
                                           GTK_STYLE_PROVIDER_PRIORITY_USER);
  }
	box = GTK_WIDGET(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3));
	gtk_container_add(GTK_CONTAINER(row), box);
  //time
  gchar *time_str = NULL;
  GDateTime *dt = NULL;
  dt = g_date_time_new_now_local();
  time_str = g_date_time_format (dt, "[%Y-%m-%d %H:%M:%S]");
	label = GTK_WIDGET(gtk_label_new(time_str));
	gtk_container_add(GTK_CONTAINER(box), GTK_WIDGET(label));
  g_free (time_str);
  g_date_time_unref (dt);
  //name
	label = GTK_WIDGET(gtk_label_new(name));
	gtk_label_set_width_chars(GTK_LABEL(label), 8);
	gtk_container_add(GTK_CONTAINER(box), GTK_WIDGET(label));
  //msg
	use_hex = gtk_switch_get_state(GTK_SWITCH(priv->use_hex));
	if (use_hex && dir) {//dir 1 read
		show = sys_uint8_to_str_calloc((uint8_t *)msg, len);
	} else {
		show = g_strdup(msg);
	}
	label = GTK_WIDGET(gtk_label_new(show));
	gtk_container_add(GTK_CONTAINER(box), GTK_WIDGET(label));
  gtk_list_box_insert (GTK_LIST_BOX (msg_box), row, -1);

  GtkAdjustment *adj = gtk_list_box_get_adjustment(GTK_LIST_BOX(msg_box));
  if (adj) {
      gtk_adjustment_set_value(adj, gtk_adjustment_get_upper(adj) - gtk_adjustment_get_page_size(adj));
      gtk_widget_show_all(row);  // Ensure the new row is shown before scrolling
      gtk_list_box_select_row(GTK_LIST_BOX(msg_box), GTK_LIST_BOX_ROW(row));
  }
	goto err;
err:
	if (show)
		g_free(show);
	return NULL;
}
typedef struct
{
  GCancellable *cancellable;
  gboolean completed;
} EventCallbackData;
typedef struct {
  GSocketConnection *conn;
  guint8 *data;
  gpointer user_data;
} ReadAsyncData;

static void
read_read_write_async_cb (GInputStream *istream,
                          GAsyncResult *result,
                          gpointer      user_data)
{
	ReadAsyncData *data = user_data;
	GError *error = NULL;
	gsize bytes_read, count = 1024;

	bytes_read = g_input_stream_read_finish (istream, result, &error);
	g_assert_no_error (error);
	data->data[bytes_read] = '\0';
	//g_print("++++:[%ld]line:%d\t%s\n", bytes_read, __LINE__, data->data);
	//show
	TsAppWindow *win;
	TsAppWindowPrivate *priv;
	win = data->user_data;
	priv = ts_app_window_get_instance_private (win);

	if (priv->socket == NULL) {
		g_print("io close\n");
		g_io_stream_close((GIOStream *)data->conn, NULL, &error);
		goto err;
	}
	win = data->user_data;
	data->data[bytes_read] = '\0';
	msg_add(win, "peer", (gchar *)data->data, bytes_read, TRUE);
	//priv = ts_app_window_get_instance_private (win);
	g_input_stream_read_async (istream,
			 data->data, count,
			 //main_buf, sizeof(main_buf),
			 G_PRIORITY_DEFAULT,
			 NULL,
			 (GAsyncReadyCallback) read_read_write_async_cb,
			 data);
err:
	return;
}
void protocol_changed_cb(GtkComboBox *widget, gpointer user_data)
{
	const gchar *protocol = NULL;
	TsAppWindow *win;
	TsAppWindowPrivate *priv;

	win = user_data;
	priv = ts_app_window_get_instance_private (win);
	protocol = gtk_combo_box_get_active_id(widget);
	g_print("change to protocol:%s\n", protocol);
	if (!g_strcmp0(protocol, "udp")) {
		gtk_label_set_text(GTK_LABEL(priv->ip_label), "peer ip");

		gtk_editable_set_editable(GTK_EDITABLE(priv->ip), TRUE);
		gtk_widget_set_can_focus (priv->ip, TRUE);

		//gtk_entry_set_text(GTK_ENTRY(priv->port), "0");
		gtk_widget_set_can_focus (priv->port, TRUE);
		gtk_editable_set_editable(GTK_EDITABLE(priv->port), TRUE);

		gtk_button_set_label(GTK_BUTTON(priv->connect), TMP_BUTTON_CONNECT);
	} else if (!g_strcmp0(protocol, TMP_PROTOCOL_TCP_CLIENT)) {
		gtk_label_set_text(GTK_LABEL(priv->ip_label), "server ip");

		gtk_editable_set_editable(GTK_EDITABLE(priv->ip), TRUE);
		gtk_widget_set_can_focus (priv->ip, TRUE);

		//gtk_entry_set_text(GTK_ENTRY(priv->port), "0");
		gtk_widget_set_can_focus (priv->port, TRUE);
		gtk_editable_set_editable(GTK_EDITABLE(priv->port), TRUE);

		gtk_button_set_label(GTK_BUTTON(priv->connect), TMP_BUTTON_CONNECT);
	} else if (!g_strcmp0(protocol, TMP_PROTOCOL_TCP_SERVER)) {
		gtk_label_set_text(GTK_LABEL(priv->ip_label), "ip");

		gtk_editable_set_editable(GTK_EDITABLE(priv->ip), FALSE);
		gtk_widget_set_can_focus (priv->ip, FALSE);

		gtk_entry_set_text(GTK_ENTRY(priv->port), "NULL");
		gtk_widget_set_can_focus (priv->port, FALSE);
		gtk_editable_set_editable(GTK_EDITABLE(priv->port), FALSE);

		gtk_button_set_label(GTK_BUTTON(priv->connect), TMP_BUTTON_OPEN);
	} else {
		g_print("invalid protocol:%s\n", protocol);
		goto err;
	}
err:
	return;
}
static void enter_cb(GObject *go, gpointer user_data)
{
	TsAppWindow *win;
	TsAppWindowPrivate *priv;
	GtkTextBuffer *buffer;
	GtkTextIter start, end;
	GSocketConnection *conn;
	GError *error = NULL;
	gint i, port, use_hex, send_len = 0;
  gsize len;
	const gchar *ip, *port_str, *obj_str = NULL, *msg = NULL;
	guint8 *send_buf = NULL, *show = NULL;

	win = user_data;
	priv = ts_app_window_get_instance_private (win);
	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(priv->input));
	gtk_text_buffer_get_bounds(buffer, &start, &end);
	msg = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
	conn = priv->socket;
	use_hex = gtk_switch_get_state(GTK_SWITCH(priv->use_hex));
	if (use_hex) {
    gchar **hex_str = NULL, *hex = NULL;
    hex_str = g_strsplit (msg, " ", 0);
    len = strlen(msg)/3;
    if (strlen(msg)%3) {
      len++;
    }
    hex = g_new (gchar, len);
    for (i = 0; i < len; i++) {
      hex[i] = g_ascii_strtoll (hex_str[i], NULL, 16);
    //  g_print ("%02x ", hex[i]);
    }
    g_strfreev (hex_str);
    send_buf = (guint8 *)hex;
    send_len = len;
	//	send_len = sys_str_to_uint8_calloc(msg, &send_buf);
	} else {
		send_buf = (guint8 *)g_strdup(msg);
		send_len = strlen(msg);
	}
	sys_uint8_print("----:", send_buf, send_len);
	obj_str = gtk_combo_box_get_active_id(GTK_COMBO_BOX(priv->protocol));
	if (!g_strcmp0(obj_str, "udp")) {
		GSocketAddress *addr;
		ip = gtk_entry_get_text(GTK_ENTRY(priv->ip));

		port_str = gtk_entry_get_text(GTK_ENTRY(priv->port));
		port = atoi(port_str);

		addr = g_inet_socket_address_new_from_string(ip, port);
		g_socket_send_to(priv->socket, addr, (gchar *)send_buf, send_len,
				NULL, &error);
		if (error) {
			g_print ("%s\n", error->message);
			g_error_free (error);
		}
	} else if (!g_strcmp0(obj_str, TMP_PROTOCOL_TCP_CLIENT)) {
		GOutputStream *ostream;
		ostream = g_io_stream_get_output_stream (G_IO_STREAM (conn));
		g_output_stream_write(ostream, send_buf, send_len, NULL, &error);
		if (error) {
			g_print ("%s\n", error->message);
			g_error_free (error);
		}
	} else if (!g_strcmp0(obj_str, TMP_PROTOCOL_TCP_SERVER)) {
		GOutputStream *ostream;
		ostream = g_object_get_data(G_OBJECT (priv->clients), "now");
		/*
		int rc = gtk_combo_box_get_active(
				GTK_COMBO_BOX(priv->clients));
		g_debug("clients:%d\n", rc);
		const char *pointer = gtk_combo_box_get_active_id(
				GTK_COMBO_BOX(priv->clients));
		gsize t = 0;
		if (pointer) {
			t = atoll(pointer);
			g_debug("o:%ld, %s\n", t, pointer);
			ostream = GINT_TO_POINTER(t);
			g_print("pointer:%p\n", ostream);
		}
		*/
		g_output_stream_write(ostream, send_buf, send_len, NULL, NULL);
	} else {
	}
	msg_add(win, "me", msg, strlen(msg), FALSE);
	goto err;
err:
	if (show)
		g_free(show);
	if (send_buf)
		g_free(send_buf);
}
void *update_config(const char *filename, const char *key, const char *value)
{
	gint add = 0;
	JsonParser *parser = NULL;
	JsonNode *root = NULL, *node = NULL;
	JsonObject *obj = NULL;
	JsonGenerator *generator = NULL;
	GError *error = NULL;
	const gchar *obj_str = NULL;

	if (g_access(filename, F_OK)) {
		g_print ("file %s not exist\n", filename);
		generator = json_generator_new();
		obj = json_object_new();
		root = json_node_alloc();
		json_node_init_object(root, obj);
		json_object_set_string_member(obj, key, value);
		json_generator_set_root(generator, root);
		json_generator_to_file(generator, filename, &error);
		if (error) {
			g_print ("Unable to parse `%s': %s\n",
					filename, error->message);
			g_error_free (error);
			g_object_unref (parser);
			goto err;
		}
	} else {
		//g_print ("file %s exist\n", filename);
		parser = json_parser_new ();
		json_parser_load_from_file (parser, filename, &error);
		if (error) {
			g_print ("Unable to parse `%s': %s\n",
					filename, error->message);
			g_error_free (error);
			g_object_unref (parser);
			goto err;
		}
		root = json_parser_get_root (parser);
		obj = json_node_get_object (root);
		g_assert(obj != NULL);
		node = json_object_get_member(obj, key);
		if (node == NULL) {
			add = 1;
			//json_node_init_string(node, value);
		} else{
			obj_str = json_object_get_string_member(obj, key);
			g_print("reset config:%s:%s\n", key, obj_str);
			if (g_strcmp0(obj_str, value)) {
				add = 1;
			}
		}
		if (add) {
			json_object_set_string_member(obj, key, value);
			generator = json_generator_new();
			json_generator_set_root(generator, root);
			json_generator_to_file(generator, filename, &error);
			if (error) {
				g_print ("Unable to parse `%s': %s\n",
						filename, error->message);
				g_error_free (error);
				g_object_unref (parser);
				goto err;
			}
		}
	}
err:
	if (root)
		json_node_free(root);
	return error;
}
static void
incoming_cb (GSocketService    *service,
                              GSocketConnection *conn,
                              GObject           *source_object,
                              gpointer           user_data)
{
	ReadAsyncData *data;
	GInputStream *istream;
	GOutputStream *ostream;
	GSocketAddress *sockaddr = NULL;
	TsAppWindow *win;
	TsAppWindowPrivate *priv;
	GInetAddress *inetaddr;
	gchar *addr;
	GError *error = NULL;
	char buf[128] = {0}, pointer[128] = {0};
	gint port = 0;

	win = user_data;
	priv = ts_app_window_get_instance_private (win);

	istream = g_io_stream_get_input_stream (G_IO_STREAM (conn));
	ostream = g_io_stream_get_output_stream (G_IO_STREAM (conn));
	sockaddr = g_socket_connection_get_remote_address(conn, &error);
	if (error) {
		g_print ("%s\n", error->message);
		g_error_free (error);
	}
	g_object_get (sockaddr, "address", &inetaddr, "port", &port,  NULL);
	addr = g_inet_address_to_string (inetaddr);
	snprintf(buf, sizeof(buf), "%s:%d", addr, port);
	g_free (addr);
	g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "%s connected\n", buf);
	g_debug("o:%p\n", ostream);
	g_object_set_data(G_OBJECT (priv->clients), "now", ostream);
	gsize t = GPOINTER_TO_SIZE(ostream);
	snprintf(pointer, sizeof(pointer), "%ld", t);
	g_debug("o:%ld, %s\n", t, pointer);
	gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(priv->clients), pointer, buf);

	data = g_new0 (ReadAsyncData, 1);
	data->conn = g_object_ref (conn);
	data->data = g_new0 (guint8, 200);
	data->user_data = win;
	g_input_stream_read_async (istream,
				 data->data,
				 20,
				 G_PRIORITY_DEFAULT,
				 NULL,
				 (GAsyncReadyCallback) read_read_write_async_cb,
				 data);
	//*cconn = g_object_ref (conn);
	goto err;
err:
	//g_free(data->data);
	//g_free(data);
	return;
}
static gpointer read_thread(gpointer user_data)
{
	TsAppWindow *win;
	TsAppWindowPrivate *priv;
	GSocket *sock;
	GSocketAddress *sa;
	GSocketConnection *conn;
	GInputStream *istream;
	GError *error = NULL;
	gint nread;
	gchar buf[128] = {0};
	const gchar *protocol = NULL;

	win = user_data;
	priv = ts_app_window_get_instance_private (win);
	protocol = gtk_combo_box_get_active_id(GTK_COMBO_BOX(priv->protocol));

	while (TRUE) {
		if (!g_strcmp0(protocol, "udp")) {
			sock = priv->socket;
			g_usleep(100);
			nread = g_socket_receive_from(sock, &sa, buf, sizeof(buf),
					NULL, &error);
			if (error && g_error_matches(error, G_IO_ERROR,
						G_IO_ERROR_CANCELLED))
				break;
		} else if (!g_strcmp0(protocol, TMP_PROTOCOL_TCP_CLIENT)) {
			conn = priv->socket;
			istream = g_io_stream_get_input_stream (G_IO_STREAM (conn));
			nread = g_input_stream_read(istream, buf, sizeof(buf) - 1,
					NULL, &error);
			if (error) {
				break;
			}
		} else if (!g_strcmp0(protocol, TMP_PROTOCOL_TCP_SERVER)) {
		}
		if (nread > 0) {
			g_print("++++:%s\n", buf);
			buf[nread] = '\0';
			msg_add(win, "peer", buf, nread, TRUE);
		}
	}
	goto err;
err:
	if (error) {
		g_print ("%s\n", error->message);
		g_error_free (error);
	}
	return NULL;
}
static void connect_cb(GObject *go, gpointer user_data)
{
	TsAppWindow *win;
	TsAppWindowPrivate *priv;
	const gchar *ip, *port_str, *protocol = NULL, *status = NULL,
	      *connect = NULL;
	gint port = 0, local_port = 0;
	gboolean rc = TRUE;
	GSocketClient *client;
	GSocket *socket = NULL;
	GError *error = NULL;
	GSocketService *service;
	GSocketConnectable *addr_s;
	GSocketConnection *conn;
	GSocketAddress *addr;

	win = user_data;
	priv = ts_app_window_get_instance_private (win);

	ip = gtk_entry_get_text(GTK_ENTRY(priv->ip));

	port_str = gtk_entry_get_text(GTK_ENTRY(priv->port));
	port = atoi(port_str);

	port_str = gtk_entry_get_text(GTK_ENTRY(priv->local_port));
	local_port = atoi(port_str);

	protocol = gtk_combo_box_get_active_id(GTK_COMBO_BOX(priv->protocol));

	//printf("sf\n\n");
	g_print("[%d]ip:%s\tlocal_port:%d port:%d\n", __LINE__, ip, local_port, port);
	//client

	status = gtk_label_get_text(GTK_LABEL(priv->status));
	connect = gtk_button_get_label(GTK_BUTTON(priv->connect));
	if (!g_strcmp0(protocol, "udp")) {
		socket = g_socket_new(G_SOCKET_FAMILY_IPV4,
				G_SOCKET_TYPE_DATAGRAM, 0, &error);
		if (error) {
			goto err;
		}
		//g_socket_set_timeout(socket, 2);
		addr = g_inet_socket_address_new_from_string("0.0.0.0", local_port);
		g_socket_bind(socket, addr, FALSE, &error);
		if (error) {
			goto err;
		}
		priv->socket = socket;
		g_thread_new("server", read_thread, win);
		//g_signal_connect (socket, "incoming",
			//	G_CALLBACK (incoming_read_write_async_cb), win);
	} else if (!g_strcmp0(protocol, TMP_PROTOCOL_TCP_CLIENT)) {
		if (!g_strcmp0(connect, TMP_BUTTON_DISCONNECT)) {
			conn = priv->socket;
			socket = g_socket_connection_get_socket(conn);
			rc = g_socket_close(socket, &error);
			if (rc == TRUE) {
				gtk_button_set_label(GTK_BUTTON(priv->connect),
						TMP_BUTTON_CONNECT);
			}
		} else if (!g_strcmp0(connect, TMP_BUTTON_CONNECT)) {
			client = g_socket_client_new ();
		//	g_socket_client_set_timeout(client, 2);
			addr_s = g_network_address_new (ip, port);
			conn = g_socket_client_connect(client, addr_s, NULL, &error);
			if (error) {
				goto err;
			}
			priv->socket = conn;
			g_thread_new("client", read_thread, win);
			gtk_label_set_text(GTK_LABEL(priv->status), "connected");
			gtk_button_set_label(GTK_BUTTON(priv->connect),
					TMP_BUTTON_DISCONNECT);
		}
	} else if (!g_strcmp0(protocol, TMP_PROTOCOL_TCP_SERVER)) {
		if (!g_strcmp0(status, TMP_STATUS_OPENED)) {
			//TODO
			///g_objects_unref(priv->clients);
			g_socket_service_stop(priv->socket);
			g_socket_listener_close(priv->socket);
			g_object_unref(priv->socket);
			priv->socket = NULL;
			gtk_label_set_text(GTK_LABEL(priv->status),
					TMP_STATUS_CLOSED);
			gtk_button_set_label(GTK_BUTTON(priv->connect),
					TMP_BUTTON_OPEN);
		} else {
			service = g_socket_service_new();
			//service = g_threaded_socket_service_new (-1);
			g_socket_listener_add_inet_port(G_SOCKET_LISTENER(service),
					local_port, NULL, &error);
			if (error) {
				goto err;
			}
			//g_signal_connect(service, "run", G_CALLBACK(handler), win);
			g_signal_connect(service, "incoming",
					G_CALLBACK(incoming_cb), win);
			priv->socket = service;
			gtk_label_set_text(GTK_LABEL(priv->status),
					TMP_STATUS_OPENED);
			gtk_button_set_label(GTK_BUTTON(priv->connect),
					TMP_BUTTON_CLOSE);
		}
	} else {
		g_print("invalid protocol:%s\n", protocol);
		goto err;
	}
	//g_socket_client_connect_async(client, addr_s, NULL, connected_cb, win);
err:
	if (error) {
		g_print ("%s\n", error->message);
		gtk_label_set_text(GTK_LABEL(priv->status), error->message);
		g_error_free (error);
	}
	return;
}
static void
ts_app_window_init (TsAppWindow *win)
{
	TsAppWindowPrivate *priv;

	gtk_window_set_title(GTK_WINDOW(win), "83net");
	gtk_window_move(GTK_WINDOW(win), 400, 200);
	priv = ts_app_window_get_instance_private (win);
	gtk_widget_init_template (GTK_WIDGET (win));
	priv->settings = g_settings_new ("org.gtk.83.net");
  g_settings_bind (priv->settings, "ip", priv->ip, "text",
                   G_SETTINGS_BIND_DEFAULT);
  g_settings_bind (priv->settings, "port", priv->port, "text",
                   G_SETTINGS_BIND_DEFAULT);
  g_settings_bind (priv->settings, "local-port", priv->local_port, "text",
                   G_SETTINGS_BIND_DEFAULT);
  g_settings_bind (priv->settings, "use-hex", priv->use_hex, "active",
                   G_SETTINGS_BIND_DEFAULT);
  g_settings_bind (priv->settings, "protocol", priv->protocol, "active-id",
                   G_SETTINGS_BIND_DEFAULT);
	g_signal_connect (priv->connect, "clicked", G_CALLBACK (connect_cb), win);
	g_signal_connect (priv->enter, "clicked", G_CALLBACK (enter_cb), win);
	g_signal_connect (priv->protocol, "changed",
			G_CALLBACK (protocol_changed_cb), win);
  //gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(priv->msg_scrolled),
   //     GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
  goto out;
out:
	return;
}

static void
ts_app_window_dispose (GObject *object)
{
	/*
	TsAppWindow *win;
	TsAppWindowPrivate *priv;

	win = APP_WINDOW (object);
	priv = ts_app_window_get_instance_private (win);
	*/

	G_OBJECT_CLASS (ts_app_window_parent_class)->dispose (object);
}

static void
ts_app_window_class_init (TsAppWindowClass *class)
{
	G_OBJECT_CLASS (class)->dispose = ts_app_window_dispose;

	gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
					       "/org/gtk/83net/main.ui");
	gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class),
			TsAppWindow, ip_label);
	gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class),
			TsAppWindow, ip);
	gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class),
			TsAppWindow, port);
	gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class),
			TsAppWindow, local_port);
	gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class),
			TsAppWindow, connect);

	gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class),
			TsAppWindow, clients);
	gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class),
			TsAppWindow, enter);

	gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class),
			TsAppWindow, input);
	gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class),
			TsAppWindow, msg_box);
	gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class),
			TsAppWindow, msg_scrolled);
	gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class),
			TsAppWindow, status);
	gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class),
			TsAppWindow, protocol);
	gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class),
			TsAppWindow, use_hex);
}

TsAppWindow *
ts_app_window_new (TsApp *ts_app)
{
  return g_object_new (TS_APP_WINDOW_TYPE, "application", ts_app, NULL);
}

void
ts_app_window_open (TsAppWindow *win,
                         GFile            *file)
{
	/*
	TsAppWindowPrivate *priv;
	gchar *basename;
	GtkWidget *scrolled, *view;
	gchar *contents;
	gsize length;
	GtkTextBuffer *buffer;
	GtkTextTag *tag;
	GtkTextIter start_iter, end_iter;

	priv = ts_app_window_get_instance_private (win);
	*/
}
